package com.OnTimeTeam.OnTime;

import java.util.Calendar;
import java.util.Random;

import com.OnTimeTeam.OnTime.Alert.MyAlarmService;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


/***************************************************************************
 * author: Daniel Huri

 * Class: AlarmSetter
 * MoreAbout: This class is responsible to cancel an existing alarm, and
 * activate an alarm which was turned off.
 **************************************************************************/

public class AlarmSetter {

	/***************************************************************************
	 * Method: AlarmSetter
	 * MoreAbout: Method receives an AlarmFeatures object, get from this object
	 * all alarms-ids (for each day there is a different id), and then it
	 * uses AlarmManager to cancel the existing alarm in the system.
	 **************************************************************************/
	public static void cancelExistingAlarm(AlarmFeatures af, Context appContext){
		
		//get all ids for all alarms in the alarm-features
		String[] alarmsIDS = af.getDaysIDS().split(", ");

		//Create an Intent which connects app with the AlarmService
		Intent alarmIntent = new Intent(appContext, MyAlarmService.class);
		
		//get all the alarms and cancel them by their id 
		for(int i = 0; i < alarmsIDS.length; ++i) {

			//create a pending intent with the od of the alarm
			PendingIntent pendingAlarmIntent = PendingIntent.getService(appContext, Integer.valueOf(alarmsIDS[i]), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
			
			//get alarm-manager
			AlarmManager alarmManager = (AlarmManager)appContext.getSystemService(Context.ALARM_SERVICE);
			
			//cancel the pending intent in alarm manager
			alarmManager.cancel(pendingAlarmIntent);
			
		}
	}//end of method cancelExistingAlarm
	
	
	/***************************************************************************
	 * Method: setBackAlarm
	 * MoreAbout: Method receives an AlarmFeatures object, get from this object
	 * all the alarms-ids (for each day there is a different id), and then it
	 * uses AlarmManager to set the turned-off alarm in the system and turn it
	 * on again.
	 **************************************************************************/
	public static void setBackAlarm(AlarmFeatures af, Context appContext, Context baseContext){
		
		//get all ids for all alarms in the alarm-features
		String[] alarmsIDS = af.getDaysIDS().split(", ");
		String[] alarmDays = af.getDaysToRepeat().split(", ");
		
		Calendar nextAlarm = null;
		
		//turn on the alarm again 
		for(int i = 0; i < alarmsIDS.length; ++i) {

			//Create Calendar and set the time in it
			Calendar alarmCal = Calendar.getInstance();//get Calendar object
			alarmCal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(af.getHour()));//set user selection
			alarmCal.set(Calendar.MINUTE, Integer.valueOf(af.getMinute()));//set user selection
			alarmCal.set(Calendar.SECOND, 0);//zero the seconds			
			alarmCal = editCalendarDay(getDayAsInt(alarmDays[i]), alarmCal);
			
			//set next closest alarm
			if(nextAlarm == null)
				nextAlarm = alarmCal;
			else if(nextAlarm.after(alarmCal))
				nextAlarm = alarmCal;
			
			
			//Create Intent which connects app
			Intent alarmIntent = new Intent(appContext, MyAlarmService.class);
			
			alarmIntent.putExtra("snoozeRepeat", af.getSnoozeRepeat());
			alarmIntent.putExtra("snoozeInterval", af.getSnoozeInterval());
			alarmIntent.putExtra("tune", af.getTune());
			alarmIntent.putExtra("volume", af.getVolume());
			alarmIntent.putExtra("label", af.getLabel()); //save the label of the alarm inside the intent
			alarmIntent.putExtra("vibration", af.getVibration()); //save vibration type inside the intent
			alarmIntent.putExtra("id", af.getID());
			alarmIntent.putExtra("hour", af.getHour());
			alarmIntent.putExtra("minute", af.getMinute());
			alarmIntent.putExtra("sort", af.getSortOfAlarm());
			alarmIntent.putExtra("days", af.getDaysToRepeat());
			alarmIntent.putExtra("ids", af.getDaysIDS());

			
			//create a pending-intent with the ID of the alarm
			PendingIntent pendingAlarmIntent = PendingIntent.getService(appContext, Integer.valueOf(alarmsIDS[i]), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
			
			//get alarm-manager and set new alarm for the wanted time
			AlarmManager alarmManager = (AlarmManager)appContext.getSystemService(Context.ALARM_SERVICE);
			alarmManager.set(AlarmManager.RTC_WAKEUP, alarmCal.getTimeInMillis(), pendingAlarmIntent);
			
		}//end of loop
		
		
        Intent notifyService = new Intent("com.OnTimeTeam.OnTime.NotificationService");
        appContext.startService(notifyService);
		
		//make toast with how much time to next alarm
		String annoncement = AlarmSetter.nextAlarmNotification(nextAlarm, appContext);
		if(annoncement != null) {
			
			final LayoutInflater inflater = (LayoutInflater) appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		View toastView = inflater.inflate(R.layout.costum_toast,null);
    		TextView textMessage = (TextView)toastView.findViewById(R.id.addressConfirmation);
    		
    		Toast confirmationToast = new Toast(appContext);
    		textMessage.setText(annoncement);
    		
			confirmationToast.setView(toastView);
			confirmationToast.setGravity(Gravity.BOTTOM|Gravity.CENTER, 0, 150);
			
			confirmationToast.setDuration(Toast.LENGTH_LONG);
			confirmationToast.show();
			
		}
		
	}
	
	
	
	public static Calendar getTimeForAlarm(SmartAlarmFeatures af, String day){
		
		//Create Calendar and set the time in it
		Calendar alarmCal = Calendar.getInstance();//get Calendar object
		alarmCal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(af.getHour()));//set user selection
		alarmCal.set(Calendar.MINUTE, Integer.valueOf(af.getMinute()));//set user selection
		alarmCal.set(Calendar.SECOND, 0);//zero the seconds			
		alarmCal = editCalendarDay(getDayAsInt(day), alarmCal);
		
		return alarmCal;
	}
	
	/***************************************************************************
	 * Method: setBackAlarm
	 * MoreAbout: Method receives an AlarmFeatures object, get from this object
	 * all the alarms-ids (for each day there is a different id), and then it
	 * uses AlarmManager to set the turned-off alarm in the system and turn it
	 * on again.
	 **************************************************************************/
	public static void setSmartAlarm(SmartAlarmFeatures af, Context appContext){
		
		//get all ids for all alarms in the alarm-features
		String[] alarmsIDS = af.getDaysIDS().split(", ");
		String[] alarmDays = af.getDaysToRepeat().split(", ");
		
		Calendar nextAlarm = null;
		
		//turn on the alarm again 
		for(int i = 0; i < alarmsIDS.length; ++i) {

			//Get the Calendar object
			Calendar alarmCal = getTimeForAlarm(af, alarmDays[i]);
			
			
			//set next closest alarm
			if(nextAlarm == null)
				nextAlarm = alarmCal;
			else if(nextAlarm.after(alarmCal))
				nextAlarm = alarmCal;
			
			//Create Intent which connects App
			Intent alarmIntent = new Intent(appContext, MyAlarmService.class);
			
			//save the label
			alarmIntent.putExtra("snoozeRepeat", af.getSnoozeRepeat());
			alarmIntent.putExtra("snoozeInterval", af.getSnoozeInterval());
			alarmIntent.putExtra("tune", af.getTune());
			alarmIntent.putExtra("volume", af.getVolume());
			alarmIntent.putExtra("label", af.getLabel()); //save the label of the alarm inside the intent
			alarmIntent.putExtra("vibration", af.getVibration()); //save vibration type inside the intent
			alarmIntent.putExtra("id", af.getID());
			alarmIntent.putExtra("hour", af.getHour());
			alarmIntent.putExtra("minute", af.getMinute());
			alarmIntent.putExtra("sort", af.getSortOfAlarm());
			alarmIntent.putExtra("days", af.getDaysToRepeat());
			alarmIntent.putExtra("ids", af.getDaysIDS());
			
			//create a pending-intent with the ID of the alarm
			PendingIntent pendingAlarmIntent = PendingIntent.getService(appContext, Integer.valueOf(alarmsIDS[i]), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
			
			//get alarm-manager and set new alarm for the wanted time
			AlarmManager alarmManager = (AlarmManager)appContext.getSystemService(Context.ALARM_SERVICE);
			alarmManager.set(AlarmManager.RTC_WAKEUP, alarmCal.getTimeInMillis(), pendingAlarmIntent);
			
		}//end of loop
		
        Intent notifyService = new Intent("com.OnTimeTeam.OnTime.NotificationService");
        appContext.startService(notifyService);
		
		//make toast with how much time to next alarm
		String annoncement = AlarmSetter.nextAlarmNotification(nextAlarm, appContext);
		if(annoncement != null) {
			
			final LayoutInflater inflater = (LayoutInflater) appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		View toastView = inflater.inflate(R.layout.costum_toast,null);
    		TextView textMessage = (TextView)toastView.findViewById(R.id.addressConfirmation);
    		
    		Toast confirmationToast = new Toast(appContext);
    		textMessage.setText(annoncement);
    		
			confirmationToast.setView(toastView);
			confirmationToast.setGravity(Gravity.BOTTOM|Gravity.CENTER, 0, 150);
			
			confirmationToast.setDuration(Toast.LENGTH_LONG);
			confirmationToast.show();
						
		}

	}//end of method 'setBackAlarm'
	
	
	
	
	
	
	
	//Create a random ID and return it
	public static int createRandomAlarmID(){
		
		//choose random number != 0 and < 50000
		int randomID = (new Random().nextInt(50000));
		
		if(randomID < 0)
			randomID *= (-1);
		
		return randomID;
	}
	
	
	public static Calendar getObjectiveTimeForAlarm(SmartAlarmFeatures af, String day){
		
		
		//Create Calendar and set the time in it
		Calendar alarmCal = Calendar.getInstance();//get Calendar object
		alarmCal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(af.getHour()));//set user selection
		alarmCal.set(Calendar.MINUTE, Integer.valueOf(af.getMinute()));//set user selection
		alarmCal.set(Calendar.SECOND, 0);//zero the seconds		
		alarmCal.set(Calendar.DAY_OF_WEEK, getDayAsInt(day));		
		
		return alarmCal;
	}

	
	/***************************************************************************
	 * Method: editCalendarDay
	 * MoreAbout: This method sets the Calendar object to the proper date
	 *  according to the day (int parameter) given
	 **************************************************************************/
	public static Calendar editCalendarDay(int day, Calendar alarmCal){
		
		//if the day of the alarm is bigger then the current day in week - add the calendar the difference
		if(day > alarmCal.get(Calendar.DAY_OF_WEEK))
			alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
		else if(day == alarmCal.get(Calendar.DAY_OF_WEEK)){//else, if the alarm is today:
			
			//if the wanted hour is biggr of the current hour - set calendar for thewanted hour
			if(alarmCal.get(Calendar.HOUR_OF_DAY) > Calendar.getInstance().get(Calendar.HOUR_OF_DAY))
				alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
			else if(alarmCal.get(Calendar.HOUR_OF_DAY) == Calendar.getInstance().get(Calendar.HOUR_OF_DAY)) {
				
				//set alarm for this week
				if(alarmCal.get(Calendar.MINUTE) >  Calendar.getInstance().get(Calendar.MINUTE))
					alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
				else // minute has past - set for next week
					alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set
				
			}
			else //the hour part - set for next week on the same hour
				alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set
		}
		else// day < today => set alarm for next week.
			alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set

		/**Now the calendar object is set to the specific time wanted by the user**/
		
		//return proper Calendar object
		return alarmCal;
	}
	
	public static Calendar editCalendarDayNotification(int day, Calendar alarmCal){
		
		//if the day of the alarm is bigger then the current day in week - add the calendar the difference
		if(day > alarmCal.get(Calendar.DAY_OF_WEEK))
			alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
		else if(day == alarmCal.get(Calendar.DAY_OF_WEEK)){//else, if the alarm is today:
			
			//if the wanted hour is biggr of the current hour - set calendar for thewanted hour
			if(alarmCal.get(Calendar.HOUR_OF_DAY) > Calendar.getInstance().get(Calendar.HOUR_OF_DAY))
				alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
			else if(alarmCal.get(Calendar.HOUR_OF_DAY) == Calendar.getInstance().get(Calendar.HOUR_OF_DAY)) {
				
				if(alarmCal.get(Calendar.MINUTE) >  Calendar.getInstance().get(Calendar.MINUTE))
					alarmCal.add(Calendar.DATE, day - alarmCal.get(Calendar.DAY_OF_WEEK));
				else // minute has past - set for next week
					alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set
				
			}
			else //the hour part - set for next week on the same hour
				alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set
		}
		else// day < today => set alarm for next week.
			alarmCal.add(Calendar.DATE, day + (7 - alarmCal.get(Calendar.DAY_OF_WEEK)));//set

		/**Now the calendar object is set to the specific time wanted by the user**/
		
		//return proper Calendar object
		return alarmCal;
	}
	
	/////////////
	//Receives string with the name of the day and returns it's number
	public static int getDayAsInt(String dayString){
		
		int day;
		
		if(dayString.equals("Sun"))
			day = 1;
		else if(dayString.equals("Mon"))
			day = 2;
		else if(dayString.equals("Tue"))
			day = 3;			
		else if(dayString.equals("Wed"))
			day = 4;			
		else if(dayString.equals("Thu"))
			day = 5;			
		else if(dayString.equals("Fri"))
			day = 6;			
		else//Saturday
			day = 7;
		
		//return the day number
		return day;
	}
	
	
	/////////////
	//Returns String with specification on how much time to next alarm according to 'nextAlarm' (parameter)
	public static String nextAlarmNotification(Calendar nextAlarm, Context appContext) {
	
		String nextAlarmString = "You have ";
	
		//Comparison
		long diff = nextAlarm.getTime().getTime()-Calendar.getInstance().getTime().getTime();
	  
		//long diffSeconds = diff / 1000 % 60;  
		
		long days = (int) (diff / (1000 * 60 * 60 * 24));
		long diffHours = (int) ((diff- (1000 * 60 * 60 * 24 * days)) / (1000 * 60 * 60));
		long diffMinutes = (int) (diff- (1000 * 60 * 60 * 24 * days) - (1000 * 60 * 60 * diffHours))/ (1000 * 60);
		
		if((days == 0) && (diffHours == 0) && (diffMinutes == 0))
			return null;
		
		
		if(days == 1)
			nextAlarmString += "one day";
		else if(days != 0)
			nextAlarmString += Long.toString(days) + " days";
		
		
		if((days == 0) && (diffHours == 1))
			nextAlarmString += "one hour";
		else if((days == 0) && (diffHours > 1))
			nextAlarmString += Long.toString(diffHours) + " hours";		
		else if((days != 0) && (diffHours == 1))
			nextAlarmString += " and one hour";
		else if((days != 0) && (diffHours > 1) && (diffMinutes == 0))
			nextAlarmString += " and " + Long.toString(diffHours) + " hours";
		else if((days != 0) && (diffHours > 1) && (diffMinutes != 0))
			nextAlarmString += ", " + Long.toString(diffHours) + " hours";
		
		if((days == 0) && (diffHours == 0) && (diffMinutes == 1) )
			nextAlarmString += "one minute";
		else if( ((days != 0) || (diffHours != 0)) && (diffMinutes == 1) )
			nextAlarmString += " and one minute";
		else if((days == 0) && (diffHours == 0) && (diffMinutes > 1) )
			nextAlarmString += Long.toString(diffMinutes) + " minutes";
		else if( ((days != 0) || (diffHours != 0)) && (diffMinutes > 1) )
			nextAlarmString += " and " + Long.toString(diffMinutes) + " minutes";
			
		nextAlarmString += " until the next alarm";
	
		return nextAlarmString;
	}

}
